home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1999 March
/
EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso
/
earcd
/
devel
/
vbcc-wos-src
/
pasm
/
output_ehf.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-01-01
|
12KB
|
416 lines
/* $VER: pasm output_ehf.c V1.2 (24.10.98)
*
* This file is part of pasm, a portable PowerPC assembler.
* Copyright (c) 1997-98 Frank Wille
*
* pasm is freeware and part of the portable and retargetable ANSI C
* compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
* pasm may be freely redistributed as long as no modifications are
* made and nothing is charged for it. Non-commercial usage is allowed
* without any restrictions.
* EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
* SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
*
*
* v1.2 (24.10.98) phx
* An empty section with reloc symbols will no longer be deleted.
* Replaced obsolete R_PPC_TOC16 by real R_PPC_SDAREL16.
* v1.1d (27.09.98) phx
* fopen() uses binary mode "b" for windoze/msdog compatibility.
* v1.1b (05.07.98) phx
* Support for Chip/Fast-Ram sections (new .section-attributes
* "C" and "F").
* v1.0 (02.05.98) phx
* Empty EHF objects contain at least an empty CODE-hunk.
* v0.9 (24.03.98) phx
* XDef for global symbols with type = @object was missing.
* Use the name set by ".file" for the unit name and not the
* one set by ".ident", which has no meaning for EHF.
* v0.7 (02.01.98) phx
* Sections after a section with HUNK_EXT were 4 bytes too large.
* Output format OFMT_ADOS support. The difference between ADOS and
* and EHF is, that ADOS uses HUNK_CODE instead HUNK_PPC_CODE and
* doesn't support any PPC-specific relocations and references types.
* This makes it possible to link simple PowerPC programs with an
* old linker, like BLink, SLink or PhxLnk.
* v0.4 (02.07.97) phx
* File created.
*/
#define OUTPUT_EHF_C
#include "ppcasm.h"
#include "ehf.h"
struct XRefNode {
struct node n;
char *sym_name;
uint8 ref_type;
int noffsets;
struct list xreflist;
};
static char *output_name;
static int nsecs = 0;
static bool exthunk;
void output_ehf(struct GlobalVars *);
static void reloc_hunk(FILE *,struct Section *,uint8,uint32);
static void unsupp_relocs(struct Section *);
static void ext_header(FILE *);
static void ext_refs(FILE *,struct GlobalVars *,struct Section *);
static void ext_defs(FILE *,struct GlobalVars *,uint32,uint8,uint32);
static uint32 word_strlen(char *);
static void write_name(FILE *,struct GlobalVars *,char *);
static void fwalign(FILE *,struct GlobalVars *,uint32);
static void fw(FILE *,void *,size_t);
static void fw4(FILE *,uint32);
void output_ehf(struct GlobalVars *gv)
{
struct Section *nextsec,*sec=(struct Section *)gv->sectionlist.first;
struct Symbol *symchain;
uint32 index;
bool ehfmode = gv->output==OFMT_EHF;
bool empty = TRUE;
FILE *fp;
/* assign an index to each valid section */
while (nextsec = (struct Section *)sec->n.next) {
if (!(sec->flags & SF_DISCARD) && sec->size > 0)
sec->index = nsecs++;
sec = nextsec;
}
/* create output file */
output_name = gv->dest_name;
if (fp = fopen(output_name,"wb")) { /* create output file */
fw4(fp,HUNK_UNIT);
if (gv->file) {
fw4(fp,word_strlen(gv->file)); /* unit name */
write_name(fp,gv,gv->file);
}
else
fw4(fp,0);
/* section loop */
sec = (struct Section *)gv->sectionlist.first;
while (nextsec = (struct Section *)sec->n.next) {
exthunk = FALSE;
if (!(sec->flags & SF_DISCARD) &&
(sec->size > 0 || (sec->flags & SF_HASSYMS))) {
uint32 styp = HUNK_DATA; /* default type */
index = sec->index;
empty = FALSE;
/* section name */
fw4(fp,HUNK_NAME);
fw4(fp,word_strlen(sec->name));
write_name(fp,gv,sec->name);
/* section type and size */
switch(sec->type) {
case ST_CODE:
styp = ehfmode ? HUNK_PPC_CODE : HUNK_CODE;
break;
case ST_DATA:
styp = HUNK_DATA;
break;
case ST_UDATA:
styp = HUNK_BSS;
break;
default: /* section type not supported in EHF/ADOS */
error(52,sec->name,(int)sec->type);
break;
}
if (sec->flags & SF_CHIP)
styp |= HUNKF_CHIP;
else if (sec->flags & SF_FAST)
styp |= HUNKF_FAST;
fw4(fp,styp);
fw4(fp,(uint32)(sec->size+3)>>2);
/* write section contents */
if (!(sec->flags & SF_UNINITIALIZED)) {
fw(fp,sec->contents,(uint32)sec->size);
fwalign(fp,gv,(uint32)sec->size);
}
/* relocation hunks */
reloc_hunk(fp,sec,R_PPC_ADDR32,HUNK_ABSRELOC32);
/* @@@ reloc_hunk(fp,sec,R_PPC_ADDR16,HUNK_ABSRELOC16); */
if (ehfmode)
reloc_hunk(fp,sec,R_PPC_REL24,HUNK_RELRELOC26);
reloc_hunk(fp,sec,R_PPC_REL14,HUNK_RELRELOC16);
reloc_hunk(fp,sec,R_PPC_REL14_BRTAKEN,HUNK_RELRELOC16);
reloc_hunk(fp,sec,R_PPC_REL14_BRNTAKEN,HUNK_RELRELOC16);
reloc_hunk(fp,sec,R_PPC_REL32,HUNK_RELRELOC32);
reloc_hunk(fp,sec,R_PPC_SDAREL16,HUNK_DREL16);
unsupp_relocs(sec); /* print unsupported relocations */
/* external references and global definitions */
ext_refs(fp,gv,sec);
ext_defs(fp,gv,index,SYM_RELOC,EXT_DEF);
if (index == 0) /* put absolute definitions in first HUNK_EXT */
ext_defs(fp,gv,0xffff,SYM_ABS,EXT_ABS);
if (exthunk)
fw4(fp,0); /* close HUNK_EXT block */
/* symbol table */
ext_defs(fp,gv,index,SYM_RELOC,EXT_SYMB);
fw4(fp,HUNK_END); /* end of this hunk */
}
sec = nextsec;
}
if (empty) { /* there was not a single section */
fw4(fp,ehfmode ? HUNK_PPC_CODE : HUNK_CODE);
fw4(fp,0);
fw4(fp,HUNK_END);
}
fclose(fp);
}
else
error(25,output_name); /* unable to create output file */
}
static void reloc_hunk(FILE *fp,struct Section *sec,uint8 r,uint32 ehfrel)
/* generate an EHF relocation hunk for a specific reloc type */
{
struct Reloc *nextrel,*rel=(struct Reloc *)sec->reloclist.first;
struct list **rlist=alloc(nsecs*sizeof(struct list *));
int *rcnt=alloczero(nsecs*sizeof(int)); /* reloc cnt for all sections */
bool hunk_required=FALSE;
int i;
for (i=0; i<nsecs; i++) { /* empty reloc lists for each section */
rlist[i] = alloc(sizeof(struct list));
initlist(rlist[i]);
}
while (nextrel = (struct Reloc *)rel->n.next) {
if (rel->type == r) {
/* move reloc node of correct type into relocssect's rlist */
remnode(&rel->n);
addtail(rlist[rel->relocsect->index],&rel->n);
rcnt[rel->relocsect->index]++;
hunk_required = TRUE;
}
rel = nextrel;
}
if (hunk_required) { /* there's at least one relocation */
fw4(fp,ehfrel); /* reloc hunk id */
for (i=0; i<nsecs; i++) {
if (rcnt[i]) {
fw4(fp,(uint32)rcnt[i]); /* number of relocations */
fw4(fp,(uint32)i); /* section index */
/* store relocation offsets */
while(rel = (struct Reloc *)remhead(rlist[i])) {
fw4(fp,(uint32)rel->offset);
free(rel);
}
}
}
fw4(fp,0); /* no more relocation entries */
}
/* free dynamically allocated rlists and rcnt array */
for (i=0; i<nsecs; free(rlist[i++]));
free(rcnt);
}
static void unsupp_relocs(struct Section *sec)
{
struct Reloc *nextrel,*rel=(struct Reloc *)sec->reloclist.first;
while (nextrel = (struct Reloc *)rel->n.next) {
error(53,elfrel_name[rel->type & ELFRELNAMMSK],rel->offset,sec->name);
rel = nextrel;
}
}
static void ext_header(FILE *fp)
{
if (!exthunk) {
exthunk = TRUE;
fw4(fp,HUNK_EXT);
}
}
static void ext_refs(FILE *fp,struct GlobalVars *gv,struct Section *sec)
{
struct list xnodelist; /* xrefs with same ref. type and symbol name */
struct XRefNode *xn,*nextxn;
struct XReference *xref;
initlist(&xnodelist);
while (xref = (struct XReference *)remhead(&sec->xreflist)) {
char *name = xref->xsymbol->name; /* name of xref'ed symbol */
uint8 rtype = xref->type;
/* ELF32 -> EHF reference type mapping */
switch (rtype) {
case R_PPC_ADDR32:
rtype = EXT_ABSREF32;
break;
case R_PPC_REL14:
case R_PPC_REL14_BRTAKEN:
case R_PPC_REL14_BRNTAKEN:
case R_PPC_ADDR16:
rtype = EXT_RELREF16;
break;
case R_PPC_SDAREL16:
rtype = EXT_DEXT16; /* small data */
break;
case R_PPC_REL24:
if (gv->output == OFMT_EHF) {
rtype = EXT_RELREF26;
break;
}
default:
error(53,elfrel_name[rtype & ELFRELNAMMSK],xref->offset,sec->name);
rtype = EXT_RELREF8; /* @@@ to keep the loop running */
break;
}
/* search appropriate XRefNode for referenced symbol and type */
xn = (struct XRefNode *)xnodelist.first;
while (nextxn = (struct XRefNode *)xn->n.next) {
if (!strcmp(name,xn->sym_name) && rtype==xn->ref_type)
break;
xn = nextxn;
}
if (nextxn==NULL) { /* we have to create a new XRefNode? */
xn = alloc(sizeof(struct XRefNode));
xn->sym_name = name;
xn->ref_type = rtype;
xn->noffsets = 0;
initlist(&xn->xreflist);
addtail(&xnodelist,&xn->n);
}
/* add new offset to xreflist for same ref. type and symbol name */
addtail(&xn->xreflist,&xref->n);
xn->noffsets++;
}
if (xnodelist.first->next) { /* at least one reference in this section? */
ext_header(fp);
while (xn = (struct XRefNode *)remhead(&xnodelist)) {
fw4(fp,((uint32)xn->ref_type << 24) | word_strlen(xn->sym_name));
write_name(fp,gv,xn->sym_name); /* symbol's name */
fw4(fp,(uint32)xn->noffsets); /* number of references */
while (xref = (struct XReference *)remhead(&xn->xreflist)) {
fw4(fp,(uint32)xref->offset); /* offset */
free(xref);
}
free(xn);
}
}
}
static void ext_defs(FILE *fp,struct GlobalVars *gv,uint32 idx,
uint8 stype,uint32 xdeftype)
{
struct Symbol *sym;
bool xdefs = FALSE;
int i;
for (i=0; i<SYMHTABSIZE; i++) {
sym = gv->symbols[i];
while (sym) {
if (sym->type==stype && (sym->info==SYMI_NOTYPE ||
sym->info==SYMI_FUNC || sym->info==SYMI_OBJECT)) {
if (idx == ((stype==SYM_RELOC) ? sym->relsect->index : 0xffff)) {
if (sym->bind > SYMB_LOCAL) {
if (!xdefs) {
xdefs = TRUE;
if (xdeftype == EXT_SYMB)
fw4(fp,HUNK_SYMBOL);
else
ext_header(fp);
}
/* generate xdef or symbol table entry */
fw4(fp,(xdeftype << 24) | word_strlen(sym->name));
write_name(fp,gv,sym->name); /* symbol's name */
fw4(fp,sym->value); /* ... and its value */
}
}
}
sym = sym->hash_chain;
}
}
if (xdefs && xdeftype==EXT_SYMB)
fw4(fp,0); /* end of symbol table for this hunk */
}
static uint32 word_strlen(char *s)
/* calculate number of 32 bit words required for
a string without terminator */
{
uint32 l;
if (l = (uint32)strlen(s))
l = (l+3)>>2;
return (l);
}
static void write_name(FILE *fp,struct GlobalVars *gv,char *name)
/* write a unit/section/symbol name word-aligned */
{
size_t nl=strlen(name);
fw(fp,name,nl);
fwalign(fp,gv,(uint32)nl);
}
static void fwalign(FILE *fp,struct GlobalVars *gv,uint32 n)
{
fw(fp,gv->alignment_bytes,(4-(n&3))&3);
}
static void fw(FILE *fp,void *buf,size_t len)
{
if (len) {
if (!fwrite(buf,1,len,fp)) {
fclose(fp);
error(26,output_name); /* write error */
}
}
}
static void fw4(FILE *fp,uint32 w)
/* write a 32 bit word, automatic endian conversion */
{
w = ECVW(w);
if (!fwrite(&w,1,sizeof(uint32),fp)) {
fclose(fp);
error(26,output_name); /* write error */
}
}